﻿using System;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.RelyingParty;
using good1.ApplicationServices.Interface;
using good1.Core;
using good1.Core.Enums;
using good1.Web.Controllers.Attributes;
using good1.Web.Controllers.Infrastructure;
using SharpArch.Core.PersistenceSupport;
using System.Collections.Generic;
using SharpArch.Web.NHibernate;
using SharpArch.Web.CommonValidator;
using SharpArch.Core;

namespace good1.Web.Controllers
{
    public class ThirdPartyIdentitiesController : BaseController
    {

        //TODO use the authenticationService, i.e. move all code to their from here
        public ThirdPartyIdentitiesController(IRepository<ThirdPartyIdentity> thirdPartyIdentityRepository, ISecurityContextService securityContext) : base(securityContext)
        {

            Check.Require(thirdPartyIdentityRepository != null, "thirdPartyIdentityRepository may not be null");
            this.thirdPartyIdentityRepository = thirdPartyIdentityRepository;
        }

        [Transaction]
        [AuthorizeAttributeCustom(RoleRequired = GoodRoles.Nimda)]
        public ActionResult Index()
        {
            IList<ThirdPartyIdentity> thirdPartyIdentitys = thirdPartyIdentityRepository.GetAll();
            return View(thirdPartyIdentitys);
        }

        [Transaction]
        [AuthorizeAttributeCustom(RoleRequired = GoodRoles.Nimda)]
        public ActionResult Show(int id)
        {
            ThirdPartyIdentity thirdPartyIdentity = thirdPartyIdentityRepository.Get(id);
            return View(thirdPartyIdentity);
        }
        
        [AuthorizeAttributeCustom(RoleRequired = GoodRoles.Nimda)]
        public ActionResult Create()
        {
            return View();
        }

        [ValidateAntiForgeryToken]
        [Transaction]
        [AuthorizeAttributeCustom(RoleRequired = GoodRoles.Nimda)]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create(ThirdPartyIdentity thirdPartyIdentity)
        {
            if (thirdPartyIdentity.IsValid())
            {
                thirdPartyIdentityRepository.SaveOrUpdate(thirdPartyIdentity);

                TempData["message"] = "The project was successfully created.";
                return RedirectToAction("Index");
            }

            MvcValidationAdapter.TransferValidationMessagesTo(ViewData.ModelState,
                thirdPartyIdentity.ValidationResults());
            return View();
        }

        [Transaction]
        [AuthorizeAttributeCustom(RoleRequired = GoodRoles.Nimda)]
        public ActionResult Edit(int id)
        {
            ThirdPartyIdentity thirdPartyIdentity = thirdPartyIdentityRepository.Get(id);
            return View(thirdPartyIdentity);
        }

        [ValidateAntiForgeryToken]
        [Transaction]
        [AuthorizeAttributeCustom(RoleRequired = GoodRoles.Nimda)]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Edit(int id, [ModelBinder(typeof(DefaultModelBinder))] ThirdPartyIdentity thirdPartyIdentity)
        {
            ThirdPartyIdentity thirdPartyIdentityToUpdate = thirdPartyIdentityRepository.Get(id);
            TransferFormValuesTo(thirdPartyIdentityToUpdate, thirdPartyIdentity);

            if (thirdPartyIdentityToUpdate.IsValid())
            {
                TempData["message"] = "The project was successfully updated.";
                return RedirectToAction("Index");
            }
            else
            {
                thirdPartyIdentityRepository.DbContext.RollbackTransaction();
                MvcValidationAdapter.TransferValidationMessagesTo(ViewData.ModelState,
                    thirdPartyIdentityToUpdate.ValidationResults());
                return View(thirdPartyIdentityToUpdate);
            }
        }

        private static void TransferFormValuesTo(ThirdPartyIdentity thirdPartyIdentityToUpdate, ThirdPartyIdentity thirdPartyIdentityForm)
        {
            thirdPartyIdentityToUpdate.ClaimedIdentifier = thirdPartyIdentityForm.ClaimedIdentifier;
            thirdPartyIdentityToUpdate.Trusted = thirdPartyIdentityForm.Trusted;
            thirdPartyIdentityToUpdate.FriendlyName = thirdPartyIdentityForm.FriendlyName;
        }

        [ValidateAntiForgeryToken]
        [Transaction]
        [AuthorizeAttributeCustom(RoleRequired = GoodRoles.Nimda)]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Delete(int id)
        {
            string resultMessage = "The thirdPartyIdentity was successfully deleted.";
            ThirdPartyIdentity thirdPartyIdentityToDelete = thirdPartyIdentityRepository.Get(id);

            if (thirdPartyIdentityToDelete != null)
            {
                thirdPartyIdentityRepository.Delete(thirdPartyIdentityToDelete);

                try
                {
                    thirdPartyIdentityRepository.DbContext.CommitChanges();
                }
                catch
                {
                    resultMessage = "A problem was encountered preventing the project from being deleted. " +
                        "Another item likely depends on this project.";
                    thirdPartyIdentityRepository.DbContext.RollbackTransaction();
                }
            }
            else
            {
                resultMessage = "The project could not be found for deletion. It may already have been deleted.";
            }

            TempData["Message"] = resultMessage;
            return RedirectToAction("Index");
        }
     


        public ActionResult LoginPopup()
        {
            return View("LoginPopup");
        }

        public ActionResult Logout()
        {
            SecurityContext.LogOut();
            return Redirect("/Home");
        }

        public ActionResult Login()
        {
            // Stage 1: display login form to user
            return View("Login");
        }

        

        [ValidateInput(false)]
        public ActionResult Authenticate(string returnUrl)
        {
            var openid = new OpenIdRelyingParty();
            var response = openid.GetResponse();
            if (response == null)
            {
                // Stage 2: user submitting Identifier
                //only going to allow google for admins for now anyway rather than asking (Request.Form["openid_identifier"])
                const string identifier = "https://www.google.com/accounts/o8/id";

                Identifier id;
                if (Identifier.TryParse(identifier, out id))
                {
                    try
                    {
                        return openid.CreateRequest(identifier).RedirectingResponse.AsActionResult();
                    }
                    catch (ProtocolException ex)
                    {
                        ViewData["Message"] = ex.Message;
                        return View("Login");
                    }
                }
                else
                {
                    ViewData["Message"] = "Invalid identifier";
                    return View("Login");
                }
            }
            else
            {
                // Stage 3: OpenID Provider sending assertion response
                switch (response.Status)
                {
                    case AuthenticationStatus.Authenticated:
                        if (!ValidAdmin(response.FriendlyIdentifierForDisplay))
                        {
                            return View("Login");
                        }
                        Session["FriendlyIdentifier"] = response.FriendlyIdentifierForDisplay;
                        FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false);
                        
                        if (!string.IsNullOrEmpty(returnUrl))
                        {
                            return Redirect(returnUrl);
                        }
                        return View("Index");

                    case AuthenticationStatus.Canceled:
                        ViewData["Message"] = "Canceled at provider";
                        return View("Login");
                    case AuthenticationStatus.Failed:
                        ViewData["Message"] = response.Exception.Message;
                        return View("Login");
                }
            }
            return new EmptyResult();
        }

       

        public Boolean ValidAdmin(string enteredClaimedIdentifier)
        {
            IList<ThirdPartyIdentity> thirdPartyIdentitys = thirdPartyIdentityRepository.GetAll();
            foreach (var list in thirdPartyIdentitys)
            {
                if (list.ClaimedIdentifier == enteredClaimedIdentifier && list.Trusted)
                {
                    SecurityContext.FriendlyName =  !string.IsNullOrEmpty(list.FriendlyName)
                                                        ? list.FriendlyName
                                                        : "ask colum for a username";
                    return true;
                }
            }

            ThirdPartyIdentity identity = new ThirdPartyIdentity
                                              {ClaimedIdentifier = enteredClaimedIdentifier, Trusted = false, CreatedDate = DateTime.Today};

            Create(identity); //not trusted but will be able to validate valid users.
            ViewData["Message"] = "Failed Login (if you think you should have access ask colum";
            return false;
        }

        private readonly IRepository<ThirdPartyIdentity> thirdPartyIdentityRepository;
    }
}
